// makehfile.cpp
// Makehfile
// Makehfile creates defns<applnbr>.h file 
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//
//

//
// MakeHFile
//
//	Makes a .h file based upon the compiled prep files
//

#include "../SDK/ToolsInterface.h"
#include <iostream>
#include <fstream>
#include <stdarg.h>
#include "../defns.h"
#include "components_helper.h"
using namespace ProteaApp1;

bool use_defines = false;

long appl_nbr;
char sqlstr[ MAX_SQL_LEN ];
char cmt_start[ 3 ];
char cmt_end[ 3 ];
char extension[ 5 ];

enum supported_languages { cplusplus=0, vbnet=1, csharp=2, phpscript=3, java=4 };
supported_languages current_lang;

class XCNewApp : public XCAppInterface, public XCAPPDICComponents {
public:
	bool GotMessage( XCMsgPort* port ) {return false;};	// Ignore

	void OnComponentLoad( XCBuffer* buffer ) {
	};

	// Start Helper functions
	void OutputHeader( fstream& output, const char* identifier ) {
		output << "\t" << cmt_start << cmt_end << endl;
		output << "\t" << cmt_start << " " << identifier << " Definitions " << cmt_end << endl;
		output << "\t" << cmt_start << cmt_end << endl;
	};

	void OutputConstant( fstream& output, const char* prefix, const char* name, const long value ) 
	{
		if ( use_defines && current_lang == cplusplus )
		{
			output << "\t#define " << prefix << name << " " << value << endl;
		}
		else
		{
			if ( current_lang == cplusplus )
			{
				output << "\tconst long " << prefix << name << " = " << value << ";" << endl;
			}
			else if ( current_lang == csharp )
			{
				output << "\tpublic const int " << prefix << name << " = " << value << ";" << endl;
			}
			else if ( current_lang == vbnet )
			{
				output << "\tPublic Const " << prefix << name << " As Long = " << value << endl;
			};
		};
	};

	void OutputTrailer( fstream& output ) {
		output << endl << endl;
	};

	void OutputConstants( fstream& output, XCBuffer* buffer, XCBuffer* base_buffer, const char* prefix, int name_field, int number_field, int count=0, ... ) {
		XCSQLGen query( this );
		XCDBStatement* stmt;
		XCTxn* txn;
		XCCompare* comp;
		XCOrder ord;
		XCField** list;

		XCField* name = buffer->GetField( name_field );
		XCField* number = buffer->GetField( number_field );

		printf( "Output: %s\n", prefix );
		printf( "Name=%s\n", name->GetFieldName() );
		printf( "Number=%s\n", number->GetFieldName() );

		// Allocate space for the comparison records
		comp = new XCCompare[ 2 + comp_count ];
		list = new XCField*[ 3 + comp_count ];
		int used = 0;

		// Create the desired buffer
		XCField* appl_nbr_fld = base_buffer->GetField( FLD_APPL_NBR );
		appl_nbr_fld->SetLong( appl_nbr );

		XCField* comp_id = base_buffer->GetField( FLD_COMPONENT_ID );

		// Query for all records
		query.MakeSELECT( buffer );

		// Add all the joins
		if (count) {
			va_list args;
			va_start(args, count);
			for (int i=0; i<count; i++) {
				XCJoin* join = va_arg( args, XCJoin* );
				query.AddJOIN( join );
			};
			va_end(args);
		};

		// Check against the appl number
		comp[0].preparen = 1;
		list[ used++ ] = appl_nbr_fld;

		// Now add the component records
		if (comp_fields) {
			bool first = true;
			comp[ used ].preparen = 1;

			t_comp_fields* tfields = comp_fields;
			while (tfields) {
				comp[ used ].format = base_buffer->GetFormatNumber();
				if (!first)
					comp[ used ].logical = logic_or;
				first = false;

				list[ used ] = comp_id->Clone();
				list[ used++ ]->MoveField( tfields->comp );
				tfields = tfields->next;
			};

			comp[ used-1 ].postparen = 1;
		};

		// Always include all appl #0 stuff
		comp[ used ].logical = logic_or;
		comp[ used-1 ].postparen = 1;
		list[ used ] = appl_nbr_fld->Clone();
		list[ used++ ]->SetLong( 0 );

		// Terminate the list and create the where clause
		list[ used ] = NULL;
		query.AddWHERE( list, comp );

		ord.format = buffer;
		query.AddORDERBY( number_field, &ord );

		// Execute the transaction
		txn = GetDatabase()->CreateTxn( NULL );
		stmt = txn->ExecuteSQL( &query );

		// Cleanup cloned fields
		for (int i=1; i<used; i++)
			list[i]->Release();

		// Output the data
		long last_number = 0;

		while (!stmt->Eof()) {
			int new_number = number->GetLong( true );
			if (new_number != last_number) {
				const char* temp = name->GetStringPtr();
				if (*temp && *temp != 32) {
					OutputConstant( 
						output, 
						prefix, 
						temp,
						number->GetLong( true ));
				};
			};
			last_number = new_number;
			stmt->MoveNext();
		};
		stmt->Release();

		txn->EndTxn( true );
		delete [] list;
		delete [] comp;
	};




	// End Helper Functions
	void OutputFormatAndFieldDefns( fstream& output ) {
		// Output the format numbers
		XCBuffer *buffer = CreateBuffer( FMT_FORMAT_DESCRIPTR );

		OutputHeader( output, "Formats" );
		OutputConstants( output, buffer, buffer, "FMT_", FLD_FORMAT_NAME, FLD_FORMAT_NUMBER );
		OutputTrailer( output );

		// Data-structures join
		XCBuffer* buffer2 = CreateBuffer( FMT_DATA_STRUCTURES );
		XCJoin join;
		join.buffer = buffer;
		join.type = join_inner;
		join.predicate = new XCCompare[2];
		join.predicate_count = 2;
		join.predicate[0].field = buffer->GetField( FLD_APPL_NBR );
		join.predicate[0].field2 = buffer2->GetField( FLD_APPL_NBR );
		join.predicate[1].field = buffer->GetField( FLD_FORMAT_NUMBER );
		join.predicate[1].field2 = buffer2->GetField( FLD_FORMAT_NUMBER );

		// Extract field descriptor
		XCBuffer* buffer3 = CreateBuffer( FMT_FIELD_DESCRIPTOR );
		XCJoin join2;
		join2.buffer = buffer2;
		join2.type = join_inner;
		join2.predicate = new XCCompare[2];
		join2.predicate_count = 2;
		join2.predicate[0].field = buffer2->GetField( FLD_APPL_NBR );
		join2.predicate[0].field2 = buffer3->GetField( FLD_APPL_NBR );
		join2.predicate[1].field = buffer2->GetField( FLD_FIELD_NUMBER );
		join2.predicate[1].field2 = buffer3->GetField( FLD_FIELD_NUMBER );

		// Output the field numbers
		OutputHeader( output, "Field" );
		OutputConstants( output, buffer3, buffer, "FLD_", FLD_FIELD_NAME, FLD_FIELD_NUMBER, 2, &join2, &join );
		OutputTrailer( output );

		// Cleanup
		buffer->Release();
		buffer2->Release();
		buffer3->Release();
	};


	void OutputTransAndUEDefns( fstream& output ) {
		// Output the transaction defns
		XCBuffer *buffer = CreateBuffer( FMT_TRANSACTION_DEFN );

		OutputHeader( output, "Transaction" );
		OutputConstants( output, buffer, buffer, "TRANS_", FLD_TRANS_CODE, FLD_TRANS_NUMBER );
		OutputTrailer( output );

		// Output user exit information
		// Extract the necessary user-exits
		XCBuffer* buffer2 = CreateBuffer( FMT_USER_EXIT_DEFNS );

		XCJoin join;
		join.buffer = buffer;
		join.type = join_inner;
		join.predicate = new XCCompare[2];
		join.predicate_count = 2;
		join.predicate[0].field = buffer->GetField( FLD_TRANS_NUMBER );
		join.predicate[0].field2 = buffer2->GetField( FLD_TRANS_NUMBER );
		join.predicate[1].field = buffer->GetField( FLD_APPL_NBR );
		join.predicate[1].field2 = buffer2->GetField( FLD_APPL_NBR );

		OutputHeader( output, "User Exits" );
		OutputConstants( output, buffer2, buffer, "UE_", FLD_USER_EXIT_NAME, FLD_USER_EXIT_NUMBER, 1, &join );
		OutputTrailer( output );

		// Cleanup
		buffer->Release();
		buffer2->Release();
	};


	void OutputErrorDefns( fstream& output ) {
		XCBuffer* buffer = CreateBuffer( FMT_MSG_MASTER, false );

		OutputHeader( output, "Error" );
		OutputConstants( output, buffer, buffer, "ERR_", FLD_MSG_NAME, FLD_MSG_NBR );
		OutputTrailer( output );

		buffer->Release();
	};



	void OutputLiterals( fstream& output ) {
		// Extract literal groups
		XCBuffer* buffer = CreateBuffer( FMT_LIT_GROUP );

		// Extract the literal relations
		XCBuffer* buffer2 = CreateBuffer( FMT_LIT_RELATE );
		XCJoin join;
		join.buffer = buffer;
		join.type = join_inner;
		join.predicate = new XCCompare[2];
		join.predicate_count = 2;
		join.predicate[0].field = buffer->GetField( FLD_APPL_NBR );
		join.predicate[0].field2 = buffer2->GetField( FLD_APPL_NBR );
		join.predicate[1].field = buffer->GetField( FLD_LIT_GROUP_NBR );
		join.predicate[1].field2 = buffer2->GetField( FLD_LIT_GROUP_NBR );

		// Extract the literal defns
		XCBuffer* buffer3 = CreateBuffer( FMT_LITERAL_DEFN );
		XCJoin join2;
		join2.buffer = buffer2;
		join2.type = join_inner;
		join2.predicate = new XCCompare[2];
		join2.predicate_count = 2;
		join2.predicate[0].field = buffer2->GetField( FLD_APPL_NBR );
		join2.predicate[0].field2 = buffer3->GetField( FLD_APPL_NBR );
		join2.predicate[1].field = buffer2->GetField( FLD_LITERAL_NUMBER );
		join2.predicate[1].field2 = buffer3->GetField( FLD_LITERAL_NUMBER );

		OutputHeader( output, "Literal" );
		OutputConstants( output, buffer3, buffer, "LIT_", FLD_LITERAL_NAME, FLD_LITERAL_NUMBER, 2, &join2, &join );
		OutputTrailer( output );
	};



	void OutputSystemDefns( fstream& output ) {
		XCBuffer* buffer = CreateBuffer( FMT_SYSTEM_VALUES, false );

		OutputHeader( output, "System value" );
		OutputConstants( output, buffer, buffer, "SYS_", FLD_FIELD_NAME, FLD_FIELD_NUMBER );
		OutputTrailer( output );

		buffer->Release();
	};


	void OutputDatabaseManual( fstream& output );
};






void XCNewApp::OutputDatabaseManual( fstream& output ) {
	output << "//@ SEC 1" << endl;
	
	int count = appdic_header->db_tables.count;
	buffer_db_tables* tables = (buffer_db_tables*)FixOffset( appdic_header->db_tables.offset );

	while (count) {
		buffer_format* format = (buffer_format*)FixOffset( tables->format );

		if (tables->view_flag != -1) {
			char temp[ 20 ];
			strcpy( temp, format->name );
			temp[ strlen( temp ) - 2 ] = 0;

			output << "//@ CHA " << temp << endl;
		} else
			output << "//@ CHA " << format->name << endl;

		int fcount = format->ds_count;
		buffer_ds* fields = (buffer_ds*)FixOffset( format->ds_offset );

		while (fcount) {
			buffer_field* field = (buffer_field*)FixOffset(fields->field_offset);
			output << "//@ DBF " << field->name << " ";

			switch( fields->data_type ) {
				case BIG_STRING:
				case STRING:
				case ALPHA_STRING:
					output << "CHAR(" << fields->max_length << ")" << endl;
					break;

				case S_INTEGER:
					output << "SMALLINT" << endl;
					break;

				case AUTONUMBER:
					output << "AUTONUMBER" << endl;
					break;

				case LITERAL_VAL:
				case D_INTEGER:
					output << "INTEGER" << endl;
					break;

				case DEC_FLOAT:
					output << "FLOAT" << endl;
					break;

				case DEC_DOUBLE:
					output << "DOUBLE" << endl;
					break;

				case DATE_DB:
					output << "DATE" << endl;
					break;

				case DATE_TIMESTAMP:
					output << "TIMESTAMP" << endl;
					break;

				case TIME_24HR_DB:
					output << "TIME" << endl;
					break;

				case XCBOOL:
					output << "CHAR(1)" << endl;
					break;

				case XCBLOB:
					output << "BLOB" << endl;
					break;

				case VAR_STRING:
					output << "VARCHAR(" << fields->max_length << ")" << endl;
					break;

				default:
					output << "<<UNKNOWN:" << fields->data_type << ">>" << endl;
					break;
			};

			fields++;
			fcount--;
		};

		// Now lookup relations
		buffer_db_relate* relates = (buffer_db_relate*)FixOffset( tables->relate_offset );
		int rcount = tables->relate_count;
		int lastone = -1;
		char temp[ 1024 ];

		if (rcount) {
			output << "//@ GRS Table constraints" << endl;
			while (rcount) {
				if (relates->type != lastone) {
					if (lastone != -1)
						output << temp << endl;
					lastone = relates->type;
			
					strcpy( temp, "//@ " );

					switch( relates->type ) {
						case dbr_primary_key:
							strcat( temp, "PRIMARY KEY(s): " );
							break;

						case dbr_unique_key:
							strcat( temp, "UNIQUE FIELDS: " );
							break;

						case dbr_index_key:
							strcat( temp, "INDEXED FIELDS: " );
							break;

						case dbr_foreign_key:
							strcat( temp, "FOREIGN KEY(s): " );
							break;

						default:
							strcat( temp, "<<UNKNOWN>>" );
							break;
					};
				} else
					strcat( temp, ", " );

				buffer_field* field = (buffer_field*)FixOffset( relates->field_offset );
				strcat( temp, field->name );

				if (relates->type == dbr_foreign_key) {
					buffer_format* fmt = (buffer_format*)FixOffset( relates->format_offset );
					strcat( temp, "(" );
					strcat( temp, fmt->name );
					strcat( temp, "." );
					strcat( temp, field->name );
					strcat( temp, ")" );
				};

				relates++;
				rcount--;
			};
			output << temp << endl;
			output << "//@ GRE " << endl;
		};	// relations

		// Move on to the next one
		tables++;
		count--;
	};
};




int main( int argc, char* argv[]) {
	int i;
	Protea::ShowIntro( "makehfile" );

	if (argc > 1 && !strcmp(argv[1],"-L"))
	{
		Protea::ShowLicense();
		return 0;
	};

	XCNewApp App;

	try {
		INFUNC( main, NULL )

		// Set defaults
		appl_nbr = 0;
		use_defines = false;
		const char* component = NULL;

		// Set C/C++ language and comment style
		current_lang = cplusplus;
		strcpy( cmt_start, "/*" );
		strcpy( cmt_end, "*/" );
		strcpy( extension, "h" );

		int current_arg = 1;
		while (current_arg < argc && appl_nbr != -1) 
		{
			const char* arg = argv[ current_arg ];
			if ( *arg == '/' ) 
			{
				// Use Defines instead of constants
				if ( *(arg+1) == 'D' || *(arg+1) == 'd' ) 
				{
					use_defines = true;
				} 
				// Use component
				else if ( *(arg+1) == 'C' || *(arg+1) == 'c' ) 
				{
					if (component == NULL) 
					{
						// Use a specified component
						if (strlen( arg )==2) 
						{
							// Must be next one in the list
							current_arg++;
							if (current_arg < argc)
							{
								component = argv[ current_arg ];
							}
						} 
						else 
						{
							component = arg+2;
						};
					} 
					else
					{
						appl_nbr = -1;
					}
				}
				// Use VB.NET definition
				else if ( *(arg+1) == 'B' || *(arg+1) == 'b' )
				{
					current_lang = vbnet;
					strcpy( cmt_start, "'" );
					strcpy( cmt_end, " " );
					strcpy( extension, "vb" );
				}
				// Use C# definition (S for Sharp)
				else if ( *(arg+1) == 'S' || *(arg+1) == 's' )
				{
					current_lang = csharp;
					strcpy( cmt_start, "//" );
					strcpy( cmt_end, " " );
					strcpy( extension, "cs" );
				}
/*				// Use PHP definition 
				else if ( *(arg+1) == 'P' || *(arg+1) == 'p' )
				{
					current_lang = phpscript;
				}
				// Use Java definition
				else if ( *(arg+1) == 'J' || *(arg+1) == 'j' )
				{
					current_lang = java;
				}
*/				else
				{
					appl_nbr = -1;
				}
			} 
			else 
			{
				// This must be the app#
				if (appl_nbr == 0)
				{
					appl_nbr = atoi( argv[ current_arg ] );
				}
				else
				{
					appl_nbr = -1;
				}
			};
			current_arg++;
		};

		if (appl_nbr <= 0) {
			cout << "Usage : makefhile <appnum> [/b] [/d] [/s] [/c COMPONENT]" << endl;
			return 0;
		};

		// Load the appdic information
		XCAppOptions myopts;
		App.GetOptions( myopts );
		myopts.no_transactions = true;
		for ( i = 0; i < num_tc; i++ )// myopts.debug_level_cutoff = 0xFF;
			myopts.debug_level_cutoff[ i ] = 0xFF;
		myopts.debug_type_filter = TRC_DATABASE;
//		myopts.debug_type_filter = 0x0;

		// myopts.no_database = true;
		App.SetOptions( myopts );

		Protea::Initialize();
		try {
			App.Initialize( argv[0], appl_nbr );
			DO_DEVTOOL_SECURITY_CHECK;
		} catch( ... ) {
			Protea::Uninitialize();
			throw;
		};
		Protea::Uninitialize();

		fstream output;

		// Create SRM Manual files 
		char* manfile = new char[ MAX_PATH ];
		sprintf( manfile, "srm%s.%s", argv[1], extension );
		output.open( manfile, ios::out );
		if (output.fail()) {
			printf( "Unable to open %s for writing!\n", manfile );
			return 1;
		};
		App.OutputDatabaseManual( output );
		output.close();

		char* filename = new char[ MAX_PATH ];
		sprintf( filename, "defns%s.%s", argv[1], extension );

		output.open( filename, ios::out );
		if (output.fail()) {
			printf( "Unable to open %s for writing!\n", filename );
			return 1;
		};

		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " Protea Tools Definitions for Application # " << appl_nbr <<"                               " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << "----------------------------------------------------------------------------" << cmt_end << endl;
		output << cmt_start << " COPYRIGHT NOTICE                                                           " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.                              " << cmt_end << endl;
		output << cmt_start << " Copyright (C) 2008 Bruce A. James                                          " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " This program is part of the Protea Project.                                " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " The Protea Project is free software; you can redistribute it and/or modify " << cmt_end << endl;
		output << cmt_start << " it under the terms of the GNU General Public License as published by the   " << cmt_end << endl;
		output << cmt_start << " Free Software Foundation, either version 3 of the License, or (at your     " << cmt_end << endl;
		output << cmt_start << " option) any later version.                                                 " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " The Protea Project is distributed in the hope that it will be useful, but  " << cmt_end << endl;
		output << cmt_start << " WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY " << cmt_end << endl;
		output << cmt_start << " or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License    " << cmt_end << endl;
		output << cmt_start << " for more details.                                                          " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " You should have received a copy of the GNU General Public License along    " << cmt_end << endl;
		output << cmt_start << " with this program.  If not, see <http://www.gnu.org/licenses/>.            " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " Please send correspondence to:                                             " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " theproteaproject@gmail.com                                                 " << cmt_end << endl;
		output << cmt_start << "----------------------------------------------------------------------------" << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " This file is automatically generated by the makehfile utility.             " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << cmt_start << " Manual changes to this file will be overwritten when makehfile is run.     " << cmt_end << endl;
		output << cmt_start << "                                                                            " << cmt_end << endl;
		output << endl;

		if ( current_lang == cplusplus )
		{
			output << "#ifndef __PROTEA_DEFN_" << appl_nbr << "__" << endl;
			output << "#define __PROTEA_DEFN_" << appl_nbr << "__" << endl;
		};
		output << endl << cmt_start << "*\n";
		if ( current_lang != cplusplus )
		{
			output << cmt_start;
		}
		output << "\\file " << filename << "\n";
		if ( current_lang != cplusplus )
		{
			output << cmt_start;
		}
		output << "\\brief Definition file based on current appdic\n" << cmt_end << endl;
		output << endl << endl;
		if ( current_lang == cplusplus )
		{
			output << "namespace ProteaApp" << appl_nbr << "\n{" << endl;
			if ( use_defines )
			{
				output << "\t#define PROTEA_APPL_NBR " << appl_nbr << "\n" << endl;
			}
			else
			{
				output << "\tconst long PROTEA_APPL_NBR = " << appl_nbr << ";\n" << endl;
			}
		}
		else if ( current_lang == csharp )
		{
			output << "namespace ProteaApp" << appl_nbr << "\n{" << endl;
			output << "public class ProteaApp" << appl_nbr << "\n{" << endl;
			output << "\tpublic const int PROTEA_APPL_NBR = " << appl_nbr << ";\n" << endl;
		}
		else if ( current_lang == vbnet )
		{
			output << "Namespace ProteaApp" << appl_nbr << "\n" << endl;
			output << "Public Class ProteaApp" << appl_nbr << "\n" << endl;
			output << "\tPublic Const PROTEA_APPL_NBR as Long = " << appl_nbr << "\n" << endl;
		}
		if ( appl_nbr != 1 )
			App.Initialize( argv[0], 1 );
		// Load the component numbers
		if (component)
			printf( "Extracting definitions for component: %s\n", component );
		XCTxn* txn = App.GetDatabase()->CreateTxn();
		App.LoadComponentNumbers( component, txn, &App, appl_nbr );
		txn->EndTxn( true );
		App.OutputFormatAndFieldDefns( output );
		App.OutputTransAndUEDefns( output );
		App.OutputLiterals( output );
		App.OutputSystemDefns( output );
		App.OutputErrorDefns( output );

		if ( current_lang == csharp )
		{
			output << "};" << endl << endl;
		}
		if ( current_lang == cplusplus || current_lang == csharp )
		{
			output << "};" << endl << endl;
		}
		else if ( current_lang == vbnet )
		{
			output << "End Class" << endl << endl;
			output << "End Namespace" << endl << endl;
		}
		if ( current_lang == cplusplus )
		{
			output << "#endif" << endl;
		};
		output.close();

		delete [] filename;
		delete[] manfile;

		OUTFUNC()
	} catch( XCToolsError& error ) {
		XCOutputCallStack( &App, error.GetErrorNumber(),error.GetDescription() );
	} catch( ... ) {
		XCOutputCallStack( &App, -1, NULL );
	};

	cout << "Ending" << endl;
	return 0;
};
